Skip to content

fix(types): remove extends ImportMeta from ModuleRunnerImportMeta#21710

Open
YevheniiKotyrlo wants to merge 1 commit intovitejs:mainfrom
YevheniiKotyrlo:fix/remove-extends-importmeta
Open

fix(types): remove extends ImportMeta from ModuleRunnerImportMeta#21710
YevheniiKotyrlo wants to merge 1 commit intovitejs:mainfrom
YevheniiKotyrlo:fix/remove-extends-importmeta

Conversation

@YevheniiKotyrlo
Copy link

Summary

ModuleRunnerImportMeta extends ImportMeta inherits all augmented properties from the global ImportMeta interface. When consumers use skipLibCheck: false with libraries that augment ImportMeta (e.g. @types/node, Expo, React Native), TypeScript raises conflicts:

error TS2717: Subsequent property declarations must have the same type.

The extends is unnecessary — the interface already explicitly declares all needed properties (url, env, hot) and has [key: string]: any as a catch-all for any additional properties (dirname, filename, main, resolve, glob).

Changes

  • packages/vite/src/module-runner/types.ts: Remove extends ImportMeta from ModuleRunnerImportMeta
  • packages/vite/src/module-runner/createImportMeta.ts: Simplify satisfies Omit<ModuleRunnerImportMeta, 'main'> as any to satisfies ModuleRunnerImportMeta as any and remove the now-unnecessary comment — main is no longer inherited from @types/node's ImportMeta augmentation

Why this is safe

  • The [key: string]: any index signature already accepts any additional properties at runtime
  • createDefaultImportMeta and createNodeImportMeta set extra properties (filename, dirname, glob, resolve, main) via the index signature — no inheritance needed
  • build-types-check (tsconfig.check.json with types: []) passes because ImportMeta without augmentations is {}, so extends ImportMeta was already a no-op in that context
  • All 5 typecheck projects pass, full build passes, ESLint passes

@sapphi-red sapphi-red added the p2-edge-case Bug, but has workaround or limited in scope (priority) label Feb 26, 2026
Copy link
Member

@sheremet-va sheremet-va left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the interface already explicitly declares all needed properties (url, env, hot) and has [key: string]: any as a catch-all for any additional properties (dirname, filename, main, resolve, glob).

This doesn't make sense? extends validates the type of these fields at least. If you are removing the extends, then you should at least move those fields over.

@sapphi-red
Copy link
Member

Does it make sense to have a type test instead of extends here?

@sheremet-va
Copy link
Member

Does it make sense to have a type test instead of extends here?

Doesn't vite already run a typecheck? The issue I have here is that filename/url just fallback to any, which should be caught by a typechecker

@sapphi-red
Copy link
Member

sapphi-red commented Feb 26, 2026

Won't it only be caught when we have extends ImportMeta? I was thinking of adding a type test so that we can catch the inconsistency between the ImportMeta in @types/node and removing extends ImportMeta so that we don't get type errors if ImportMeta is modified somewhere (and also add the missing fields to ModuleRunnerImportMeta).

@sheremet-va
Copy link
Member

Won't it only be caught when we have extends ImportMeta? I was thinking of adding a type test so that we can catch the inconsistency between the ImportMeta in @types/node and removing extends ImportMeta so that we don't get type errors if ImportMeta is modified somewhere (and also add the missing fields to ModuleRunnerImportMeta).

Okay, that makes sense

- Remove `extends ImportMeta` to prevent TS2717 "subsequent property
  declarations must have the same type" in consumer projects using
  skipLibCheck: false with augmented ImportMeta
- Add explicit fields (dirname, filename, resolve, glob, main) that were
  previously inherited, so consumers get real types instead of falling
  through the `[key: string]: any` index signature
- Add `main: false` to createDefaultImportMeta (previously only set in
  createNodeImportMeta)
- Remove `satisfies Omit<ModuleRunnerImportMeta, 'main'> as any` — the
  function return type annotation handles the check, and with explicit
  fields the Omit workaround is no longer needed
- Add type test verifying ModuleRunnerImportMeta is assignable to
  ImportMeta (including @types/node augmentations) — catches future
  inconsistencies without causing declaration-level conflicts
@YevheniiKotyrlo YevheniiKotyrlo force-pushed the fix/remove-extends-importmeta branch from 9f3d1b8 to 414de13 Compare February 26, 2026 12:34
@YevheniiKotyrlo
Copy link
Author

Thanks for the feedback! Updated the PR:

  1. Added explicit fields to ModuleRunnerImportMetadirname, filename, resolve, glob, and main — so consumers get real types instead of falling through [key: string]: any
  2. Made main: boolean required and added main: false to createDefaultImportMeta (matches @types/node where main is non-optional)
  3. Added a type test in src/module-runner/__tests_dts__/importMeta.ts that verifies ModuleRunnerImportMeta is assignable to ImportMeta (including @types/node augmentations) — replaces the compile-time guarantee extends provided, without causing TS2717 in consumer projects
  4. Removed satisfies Omit<ModuleRunnerImportMeta, 'main'> as any per @sapphi-red's suggestion
  5. Wired the new type test into the typecheck script (now 6 projects)

All gates pass: typecheck (6 projects), build (bundle + DTS + check), ESLint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

p2-edge-case Bug, but has workaround or limited in scope (priority)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants